# coding: utf-8

#证书
import os
import datetime
import File
import RSA_op
import SHA256_op
import FTP_op

#根据使用者姓名和公钥生成申请文件
def apply_certificate(name):
    #name = input("请输入证书使用者姓名:")
    public_file = name+"_public.key"
    if os.path.exists(public_file)==False:
        return -1
    public_key = File.read_file_hex(public_file)
    
    write_name = name + "_apply.csr"
    f = open(write_name,"w")
    f.write("user name:" + name + '\n')
    f.write("user public key:" + public_key + '\n')
    f.close()
    return 1

#签发证书
#追加CA信息
def write_CA_info(username):
    #读取CA.ini配置文件
    with open('CA.ini',"r") as f:
        CAinfo = f.read() 
    with open(username+'_CA.csr',"a+") as f:
        f.write(CAinfo+'\n')
    print("追加写入CA信息完成")

#追加写入时间
def write_time(username, start, use):
    # 将输入的开始和有效时间(单位为天)转换为Python可处理的时间
    start_change_time = datetime.timedelta(days=start)
    use_time = datetime.timedelta(days=use)
    #获取当前时间并加入时间差值
    #统一使用UTC时间，避免时区不同带来的影响
    start_time = (datetime.datetime.utcnow() + start_change_time).isoformat()
    stop_time = (datetime.datetime.utcnow() + start_change_time + use_time).isoformat()
    with open(username+'_CA.csr',"a+") as f:
        f.write("start time:"+start_time+'\n')
        f.write("end time:"+stop_time+'\n')

#追加写入签名
def write_sign(username, sign):
    sign_str = hex(sign)[2:].upper()
    with open(username+'_CA.csr',"a+") as f:
        f.write("sign:"+sign_str)

#签发证书(CA补齐证书内容)
def finish_certificate(name, start, use):
    apply_file = name+"_apply.csr"
    if os.path.exists(apply_file)==False:  #申请文件不存在
        return -1
    if os.path.exists("CA.ini")==False:  #CA的配置文件不存在
        return -2
    File.copy_file(name)  #复制证书申请文件作为副本
    File.write_id(name)  #写入序列号(SHA256值)
    write_CA_info(name)  #写入CA信息
    write_time(name, start, use)  #写入时间信息
    #计算签名的部分
    sha_all = SHA256_op.cal_file_sha256(name+'_CA.csr')
    sha_all = int(sha_all, 16)  #将十六进制结果转换为十进制
    pri_key = File.read_file_dec('CA_private.key')  #读取公钥
    pub_key  = File.read_file_dec('CA_public.key') #读取私钥
    sign = RSA_op.exp_mode(sha_all, pri_key, pub_key)  #计算签名值
    write_sign(name, sign)  #将签名写回文件
    return 1  #返回执行成功值为1

#校验证书
def verify_certificate(name):
    apply_file = name+"_CA.csr"
    t_str = ''
    try:
        with open(apply_file, "r") as f:
            for i in range(4):  #标准格式中前四行不需要特殊处理
                t_str += f.readline()
            t_start = f.readline()  #第五行是生效时间
            t_str += t_start
            t_stop = f.readline()  #第六行是过期时间
            t_str += t_stop
            t_sign = f.readline()[5:]  #第七行是前面，需要去掉前面几个字符的说明
    except:  #证书不存在时报错
        return -1

    #检查证书是否在吊销列表
    pub_key  = File.read_file_dec('CA_public.key')
    id_num = t_str.find('user id')  #查找表示序列号的字段并进行提取
    u_id = t_str[id_num+8:][:64]
    u_id = int(u_id, 16)
    try:
        with open('CA_cancel.crl', 'r') as f:
            while True:
                t_id = f.readline()
                if not t_id:
                    break
                t_id = int(t_id, 16)
                t_decrypt = RSA_op.exp_mode(t_id, 65537, pub_key)
                if u_id == t_decrypt:  #在吊销列表中查找到当前证书的序列号，说明已被吊销
                    return -2
    except:
        print("提示：未找到吊销列表")

    #验证证书时间
    t_start = t_start[11:].replace("\n",'')
    t_stop = t_stop[9:].replace("\n",'')
    #设置时间格式，将读取到的时间字符串转换为程序可处理的时间格式
    UTC_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
    nowTime = datetime.datetime.utcnow()
    startTime = datetime.datetime.strptime(t_start, UTC_FORMAT)
    endTime = datetime.datetime.strptime(t_stop, UTC_FORMAT)
    if ((startTime - nowTime).days >0):  #生效时间晚于当前时间，证书未生效
        return -3
    elif ((endTime - nowTime).days <0):  #过期时间早于当前时间，证书已过期
        return -4
    
    #验证签名
    t_sign = int(t_sign, 16)
    t_sha = SHA256_op.cal_sha256(t_str)
    t_decrypt = RSA_op.exp_mode(t_sign, 65537, pub_key)
    t_decrypt = hex(t_decrypt)[2:].upper()
    if(t_sha == t_decrypt):  #两次结果一致，验证通过
        return 1
    else: #两次结果不一致，验证失败
        return 0

#吊销证书
def cancel_certificate(name):
    try:
        with open(name+"_CA.csr", "r") as f:
            while True:
                t_str = f.readline()
                if t_str.find("user id")!=-1:
                    t_str = t_str[8:]
                    break
    except:  #证书文件不存在
        return -1
    #十六进制转换为十进制
    cancel_id = int(t_str, 16)
    #将序列号转为十进制，利用RSA签名后写入吊销列表
    with open("CA_cancel.crl", 'a+') as f:
        pri_key = File.read_file_dec('CA_private.key')
        pub_key  = File.read_file_dec('CA_public.key')
        user_id = RSA_op.exp_mode(cancel_id, pri_key, pub_key)
        id_str = hex(user_id)[2:].upper()
        f.write(id_str+'\n')
        #print("追加写入证书吊销信息完成\n")
        return 1